/* DicomFileReader.cpp -- Source file for class DicomFileReader
*
* TotalDcmLister - A lister plugin for Total Commander for listing DICOM File content.
*
* Copyright (C) 2015 Captain Stark
*
* This software may be modified and distributed under the terms of the MIT license.
* See the COPYRIGHT file at the top-level directory of this distribution for details.
*/

#include "stdafx.h"
#include "DicomFileReader.h"
#include "StringConverter.h"

#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"
#include "dcmtk/dcmdata/dcpath.h"

using namespace std;

/// <summary>
/// Initializes a new instance of the <see cref="DicomFileReader"/> class.
/// </summary>
/// <param name="dcmDataset">The DICOM file to extract data from.</param>
DicomFileReader::DicomFileReader(const string& fileName)
: m_dicomDataset(nullptr), m_loadedSopClass(L"Unknown SOP Class")
{
   OFCondition status = m_dicomFile.loadFile(fileName.c_str());

   if (status.good())
   {
      m_dicomDataset = m_dicomFile.getDataset();
       
      OFString value;
      OFCondition status = m_dicomDataset->findAndGetOFString(DCM_SOPClassUID, value);

      if (status.good())
      {
         const char* sopClassName = dcmFindNameOfUID(value.c_str(), "Unknown SOP Class");
         m_loadedSopClass = NarrowToWide(sopClassName);
      }
   }
}

/// <summary>
/// Finalizes an instance of the <see cref="DicomFileReader"/> class.
/// </summary>
DicomFileReader::~DicomFileReader()
{
}

/// <summary>
/// Determines whether the specified DICOM attribute exists in the loaded file.
/// </summary>
/// <param name="tag">The DICOM tag (full DICOM path allowed).</param>
/// <returns>True, when the DICOM attribute exists. False otherwise.</returns>
bool DicomFileReader::HasAttribute(const wstring& tag)
{
   if (nullptr == m_dicomDataset)
   {
      return false;
   }

   DcmPathProcessor pathProcessor;
   OFString searchPath = WideToNarrow(tag).c_str();

   OFCondition result = pathProcessor.findOrCreatePath(m_dicomDataset, searchPath, OFFalse);

   return result.good();
}

/// <summary>
/// Gets the DICOM attribute's value as string or the specified default value in case of error.
/// </summary>
/// <param name="tag">The DICOM tag (full DICOM path allowed).</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>The DICOM attribute's value as string.</returns>
wstring DicomFileReader::GetAttributeValue(const wstring& tag, const wstring& defaultValue)
{
   if (nullptr == m_dicomDataset)
   {
      return defaultValue;
   }

   DcmPathProcessor pathProcessor;
   OFString searchPath = WideToNarrow(tag).c_str();

   OFCondition result = pathProcessor.findOrCreatePath(m_dicomDataset, searchPath, OFFalse);
   if (result.good())
   {
      OFList<DcmPath*> searchResults;
      Uint32 numberOfResults = pathProcessor.getResults(searchResults);

      if (0 < numberOfResults)
      {
         DcmPath* searchResult = searchResults.front();

         DcmPathNode* leafNodeInPath = searchResult->back();

         if (NULL != leafNodeInPath)
         {
            DcmElement* element = OFstatic_cast(DcmElement*, leafNodeInPath->m_obj);

            OFString value;
            result = element->getOFStringArray(value);

            if (result.good())
            {
               return NarrowToWide(value.c_str());
            }
         }
      }
   }

   return defaultValue;
}

/// <summary>
/// Gets the name of the SOP class currently loaded.
/// </summary>
/// <returns></returns>
wstring DicomFileReader::GetSopClassName()
{
   return m_loadedSopClass;
}